package pl.edu.agh.neuraleconomy.core.ta.advice;

import java.util.Date;
import java.util.List;

import lombok.Setter;
import pl.edu.agh.neuraleconomy.core.nn.CoreUtils;
import pl.edu.agh.neuraleconomy.core.simulation.SimulationService;
import pl.edu.agh.neuraleconomy.core.ta.indicator.EMACalculator;
import pl.edu.agh.neuraleconomy.model.exchange.Company;
import pl.edu.agh.neuraleconomy.model.exchange.Exchange;

public class EMAAdvisor extends IndicatorAdvisor {
	private int period;
	@Setter
	private int trendLen = 5;
	@Setter
	private double priceFactor = 0.1;

	public EMAAdvisor(int period) {
		super();
		this.period = period;
		this.calculator = new EMACalculator(period);
	}

	public Advice getAdvice(Company company, Date date) {
		List<Exchange> data = getData(company, date);
		if (data.size() < period * 2) {
			logger.warn("Not enough data to give advice for company " + company.getName());
			return null;
		}
		double[] ema = calculator.calculate(CoreUtils.toDoubleArray(data));

		double todaysPrice = new SimulationService().getSharePrice(company, date).doubleValue();
		double todaysEMA = ema[ema.length - 1];

		Boolean trend = findTrend(ema);

		if (trend == null) {
			return new Advice(company, AdviceType.STAY, 0);
		}

		if (trend && todaysPrice < ((double) 1 + priceFactor) * todaysEMA) {
			return new Advice(company, AdviceType.BUY, 90);
		}

		if (!trend && todaysPrice > ((double) 1 - priceFactor) * todaysEMA) {
			return new Advice(company, AdviceType.SELL, 90);
		}

		return new Advice(company, AdviceType.STAY, 0);
	}

	private List<Exchange> getData(Company company, Date date) {
		return exchangeDao.getLatestByCompanyIncludeDate(company.getId(), date, (long) period * 2);
	}

	private Boolean findTrend(double ema[]) {
		Boolean trend = null;

		if (ema[ema.length - 1 - trendLen] < ema[ema.length - 1]) {
			trend = true;
		} else {
			trend = false;
		}

		for (int i = ema.length - trendLen; i < ema.length; i++) {
			if (trend) {
				if (ema[i - 1] > ema[i]) {
					return null;
				}
			}

			if (!trend) {
				if (ema[i - 1] < ema[i]) {
					return null;
				}
			}
		}

		return trend;
	}

}
